package com.ksyun.alert.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ksyun.alert.dto.*;
import com.ksyun.alert.entity.AlertRulesDO;
import com.ksyun.alert.entity.MonitorDatasDO;
import com.ksyun.alert.service.AlertMetricsService;
import com.ksyun.alert.service.AlertRulesService;
import com.ksyun.alert.vo.AlertRecordVO;
import com.ksyun.alert.customException.SkyAlertException;
import com.ksyun.alert.entity.AlertRecordsDO;
import com.ksyun.alert.mapper.AlertRecordsMapper;
import com.ksyun.alert.result.PageResult;
import com.ksyun.alert.service.AlertRecordsService;
import com.ksyun.alert.utils.TimestampConverter;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * 告警记录表接口实现层
 * @author 蓝
 */
@Service
public class AlertRecordsServiceImpl extends ServiceImpl<AlertRecordsMapper, AlertRecordsDO> implements AlertRecordsService {
    @Resource
    private AlertRecordsMapper recordsMapper;

    @Resource
    private AlertRulesService alertRulesService;

    @Resource
    private AlertMetricsService alertMetricsService;

    @Override
    public void insert(AlertRecordsDO alertrecords) {
        recordsMapper.insert(alertrecords);
    }

    @Override
    public PageResult selectPageByConditions(PageQueryDTO pageQueryDTO) {
        //页码和分页大小
        int page = pageQueryDTO.getPage();
        int pageSize = pageQueryDTO.getPageSize();
        //主机名
        String hostName = pageQueryDTO.getHostName();
        //起始结束时间
        LocalDateTime startTime = pageQueryDTO.getStartTime();
        LocalDateTime endTime = pageQueryDTO.getEndTime();
        //分页
        Page<AlertRecordsDO> alertPage = new Page<>(page, pageSize);
        //条件构造
        LambdaQueryWrapper<AlertRecordsDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(hostName != null, AlertRecordsDO::getHostName, hostName);
        if (startTime != null) {
            int time = TimestampConverter.localDateTimeToInt(startTime);
            queryWrapper.ge(AlertRecordsDO::getTimestamp, time);
        }
        if (endTime != null) {
            int time = TimestampConverter.localDateTimeToInt(endTime);
            queryWrapper.le(AlertRecordsDO::getTimestamp, time);
        }
        Page<AlertRecordsDO> recordPages = recordsMapper.selectPage(alertPage, queryWrapper);
        //构造返回值
        List<AlertRecordVO> alertRecordVOS = recordPages.getRecords().stream().map(record -> AlertRecordVO.builder()
                .id(record.getId())
                .ruleId(record.getRuleId())
                .alertMessage(record.getAlertMessage())
                .severity(record.getSeverity())
                .hostName(record.getHostName())
                .occurrenceTime(TimestampConverter.intToDateTimeString(record.getTimestamp()))
                .build()).collect(Collectors.toList());
        return new PageResult(recordPages.getTotal(), alertRecordVOS);
    }

    @Override
    public List<RecordTime2CountDTO> selectRecordTime2Counts(TimeStartEndDTO timeStartEndDTO) {
        //起始终止时间戳
        int start = -1;
        int end = -1;
        try {
            start = TimestampConverter.stringToTimestamp(timeStartEndDTO.getStartTime());
            end = TimestampConverter.stringToTimestamp(timeStartEndDTO.getEndTime());
        } catch (Exception e) {
            throw new SkyAlertException("时间格式不正确");
        }
        LambdaQueryWrapper<AlertRecordsDO> queryWrapper = new LambdaQueryWrapper<>();
        //时间戳范围
        queryWrapper.ge(start != -1, AlertRecordsDO::getTimestamp, start);
        queryWrapper.le(end != -1, AlertRecordsDO::getTimestamp, end);
        //只查询时间戳字段
        queryWrapper.select(AlertRecordsDO::getTimestamp);
        List<AlertRecordsDO> list = list(queryWrapper);
        //所有时间戳集合
        List<Long> timestamps = list.stream().map(AlertRecordsDO::getTimestamp).collect(Collectors.toList());
        return getListRecord2Count(timestamps);
    }

    @Override
    public AlertQueryRespDTO queryAlertsByPeriodAndReqId(AlertQueryReqDTO alertQueryReqDTO) {
        LambdaQueryWrapper<AlertRecordsDO> queryWrapper = Wrappers.lambdaQuery(AlertRecordsDO.class)
                                                                    .ge(AlertRecordsDO::getTimestamp, TimestampConverter.stringToTimestamp(alertQueryReqDTO.getStart()))
                                                                    .le(AlertRecordsDO::getTimestamp, TimestampConverter.stringToTimestamp(alertQueryReqDTO.getEnd()));
        List<AlertRecordsDO> alertRecordsDOList = this.list(queryWrapper);
        List<AlertRulesDO> rules = alertRulesService.getRules();
        Map<Integer, AlertRulesDO> rulesMap = rules.stream()
                .collect(Collectors.toMap(AlertRulesDO::getId, Function.identity()));

        List<AlertQueryDataRespDTO> data = alertRecordsDOList.stream()
                .map(alertRecordsDO -> {
                    AlertRulesDO rulesDO = rulesMap.get(alertRecordsDO.getRuleId());
                    Float value = null;
                    if(rulesDO.getType() == 0){
                        value = alertMetricsService.selectRecordByAlertIdAneMetricName(alertRecordsDO.getId(), rulesDO.getMetric());
                    }else if(rulesDO.getType() == 1){
                        value = alertMetricsService.selectRecordByAlertIdAneMetricName(alertRecordsDO.getId(), "expressionValue");
                    }

                    return AlertQueryDataRespDTO.builder()
                            .condition(rulesDO.getExpression() + rulesDO.getComparison() + rulesDO.getThreshold())
                            .timestamp((alertRecordsDO.getTimestamp().intValue()))
                            .value(value)
                            .build();
                })
                .collect(Collectors.toList());

        return AlertQueryRespDTO.builder()
                .total(alertRecordsDOList.size())
                .requestId(alertQueryReqDTO.getRequestId())
                .data(data)
                .build();
    }

    private List<RecordTime2CountDTO> getListRecord2Count(List<Long> timestamps) {
        LinkedHashMap<Long, Integer> hashMap = new LinkedHashMap<>();
        for (Long timestamp : timestamps) {
            hashMap.put(timestamp, hashMap.getOrDefault(timestamp, 0) + 1);
        }
        ArrayList<RecordTime2CountDTO> arrayList = new ArrayList<>(hashMap.size());
        for (Map.Entry<Long, Integer> entry : hashMap.entrySet()) {
            String key = TimestampConverter.intToDateTimeString(entry.getKey());
            Integer value = entry.getValue();
            arrayList.add(new RecordTime2CountDTO(key, value));
        }
        return arrayList;
    }
}